﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DataSetEncryption.cs" company="None">
//   <Author>Adrian von Allmen, 2013</Author>
//   <Author>ADO.net 3.5 Cookbook (978-0-596-10140-4), Chapter 6.11</Author>
// </copyright>
// <summary>
//   Encryption Classes for DataSet Export, based on 
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace CrumbleLibrary
{
    using System;
    using System.Data;
    using System.Diagnostics.CodeAnalysis;
    using System.IO;
    using System.Security.Cryptography;

    /// <summary>
    /// The data set encryption.
    /// </summary>
    public static class DataSetEncryption
    {
        // ReSharper disable UnusedMember.Local
        // ReSharper disable CSharpWarnings::CS0162
        // ReSharper disable HeuristicUnreachableCode
        private enum Algorithm { DES, RC2, Rijndael, TripleDES };

        private const int KeySize = 256;
        private static RSACryptoServiceProvider rSAReceiver = new RSACryptoServiceProvider();

        private const int SymmetricAlgorithm = (int)Algorithm.Rijndael;

        // DES key and IV
        private static readonly Byte[] DESKey = { 0x01, 0x02, 0x03, 0x11, 0x05, 0x06, 0x07, 0x08 };
        private static readonly Byte[] DESIV = { 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 };
        // RC2 key and IV
        private static readonly Byte[] RC2Key = {0x18, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                                                 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
        private static readonly Byte[] RC2IV = {0x12, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
                                                0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
        // Rijndael key and IV
        private static readonly Byte[] RijndaelKey = {0x22, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
                                                      0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F};
        private static readonly Byte[] RijndaelIV = {0x32, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
                                                     0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F};
        // triple DES key and IV
        private static readonly Byte[] TriDESKey = {0x12, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                                                    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
                                                    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17};
        private static readonly Byte[] TriDESIV = {0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
                                                   0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
                                                   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37};

        public static void SymmetricEncryptDataSet(DataSet dsSource, string fileName)
        {
            // symmetric algorithms
            SymmetricAlgorithm sa;
            byte[] key;
            byte[] iV;
            switch (SymmetricAlgorithm)
            {
                case (int)Algorithm.DES:
                    sa = new DESCryptoServiceProvider();
                    key = DESKey;
                    iV = DESIV;
                    break;
                case (int)Algorithm.RC2:
                    sa = new RC2CryptoServiceProvider { KeySize = KeySize };
                    key = RC2Key;
                    iV = RC2IV;
                    break;
                case (int)Algorithm.Rijndael:
                    sa = new RijndaelManaged { KeySize = KeySize };
                    key = RijndaelKey;
                    iV = RijndaelIV;
                    break;
                case (int)Algorithm.TripleDES:
                    sa = new TripleDESCryptoServiceProvider();
                    key = TriDESKey;
                    iV = TriDESIV;
                    break;
            }

            var fsWrite = new FileStream(fileName, FileMode.Create, FileAccess.Write);
            var cs = new CryptoStream(fsWrite, sa.CreateEncryptor(key, iV), CryptoStreamMode.Write);
            dsSource.WriteXml(cs, XmlWriteMode.WriteSchema);
            cs.Close();
            fsWrite.Close();
        }

        public static DataSet SymmetricDecryptDataSet(string fileName)
        {
            var fsRead = new FileStream(fileName, FileMode.Open, FileAccess.Read);
            SymmetricAlgorithm sa;
            byte[] key;
            byte[] iV;
            switch (SymmetricAlgorithm)
            {
                case (int)Algorithm.DES:
                    sa = new DESCryptoServiceProvider();
                    key = DESKey;
                    iV = DESIV;
                    break;
                case (int)Algorithm.RC2:
                    sa = new RC2CryptoServiceProvider { KeySize = KeySize };
                    key = RC2Key;
                    iV = RC2IV;
                    break;
                case (int)Algorithm.Rijndael:
                    sa = new RijndaelManaged { KeySize = KeySize };
                    key = RijndaelKey;
                    iV = RijndaelIV;
                    break;
                case (int)Algorithm.TripleDES:
                    sa = new TripleDESCryptoServiceProvider();
                    key = TriDESKey;
                    iV = TriDESIV;
                    break;
            }

            var cs = new CryptoStream(fsRead, sa.CreateDecryptor(key, iV), CryptoStreamMode.Read);
            var ds = new DataSet();
            ds.ReadXml(cs, XmlReadMode.ReadSchema);
            cs.Close();
            fsRead.Close();
            return ds;
        }

    }
}
